package slice

import (
	"errors"
	"fmt"
)

// 常量定义
const (
	// MinShrinkCap 最小缩容容量
	MinShrinkCap = 4
)

// 异常定义
var (
	// ErrSliceIndexOutOfRange 索引越界异常
	ErrSliceIndexOutOfRange = errors.New("slice index out of range")

	// ErrSliceEmpty 空切片异常
	ErrSliceEmpty = errors.New("slice is empty")
)

// DeleteAt 删除切片指定索引位置的元素,并返回删除后的新切片
// 如果索引越界,则返回 ErrSliceIndexOutOfRange
func DeleteAt[T any](src []T, idx int) ([]T, error) {
	length := len(src)
	if idx < 0 || idx >= length { //校验索引
		return nil,
			fmt.Errorf("%w: slice index out of range! index: %d, actual length: %d", ErrSliceIndexOutOfRange, idx, length)
	}

	//拷贝源切片的值
	for i := idx; i < length-1; i++ {
		src[i] = src[i+1]
	}

	//返回新切片
	return src[:length-1], nil
}

// Shrink 对切片进行缩容,并返回缩容后的新切片
// 如果切片为空,则返回 ErrSliceEmpty
func Shrink[T any](src []T) ([]T, error) {
	length := len(src)
	if length == 0 { //空值校验
		return nil, fmt.Errorf("%w: slice is empty! ", ErrSliceEmpty)
	}
	capacity := cap(src)

	//切片容量校验
	newCap, changed := ensureCapacity(length, capacity)
	if !changed { //无需缩容,直接返回
		return src, nil
	}

	//创建并拷贝新切片
	shrunk := make([]T, 0, newCap)
	shrunk = append(shrunk, src...)

	//返回缩容后的新切片
	return shrunk, nil
}

// 处理切片容量
func ensureCapacity(length, capacity int) (int, bool) {
	if capacity <= MinShrinkCap { //未达到最小缩容阈值,无需处理
		return capacity, false
	}

	//目前粗暴地将新cap直接缩容为len,该算法可优化
	return length, true
}
